/*
 * 实现RPC的路由功能，将注册到Dispatcher模块针对rpc请求进行回调处理
 */
#pragma once
#include "../common/net.hpp"
#include "../common/message.hpp"

namespace jsonrpc
{
    namespace server
    {
        enum class ValueType
        {
            STRING,
            INTEGRAL,
            NUMERIC,
            BOOL,
            OBJECT,
            ARRAY
        };
        class ServiceDescribe
        {
        public:
            using ptr = std::shared_ptr<ServiceDescribe>;
            // 服务回调函数，参数为请求参数和响应参数
            using ServiceCallback = std::function<void(const Json::Value &, Json::Value &)>;
            using ParametersDescribe = std::pair<std::string, ValueType>;

            ServiceDescribe(std::string &&_method_name, std::vector<ParametersDescribe> &&_params_desc,
                            ValueType _return_type, ServiceCallback &&_callback) : method_name(std::move(_method_name)),
                                                                                   callback_func(std::move(_callback)),
                                                                                   params_desc(std::move(_params_desc)),
                                                                                   return_type(_return_type) {}
            const std::string &getMethod() { return method_name; }
            // 检查收到请求中的参数
            bool checkParams(const Json::Value &params)
            {
                for (const auto &param : params_desc)
                {
                    if (!params.isMember(param.first))
                    {
                        LOG_ERROR("parameter %s not exist", param.first.c_str());
                        return false;
                    }
                    if (!checkType(param.second, params[param.first]))
                    {
                        LOG_ERROR("parameter %s type error", param.first.c_str());
                        return false;
                    }
                }
                return true;
            }
            // 调用回调函数
            bool callback(const Json::Value &params, Json::Value &return_value)
            {
                callback_func(params, return_value);
                if (!checkReturnType(return_value))
                {
                    LOG_ERROR("return value type error");
                    return false;
                }
                return true;
            }

        private:
            bool checkReturnType(const Json::Value &return_value)
            {
                return checkType(return_type, return_value);
            }
            bool checkType(ValueType type, const Json::Value &value)
            {
                switch (type)
                {
                case ValueType::STRING:
                    return value.isString();
                case ValueType::INTEGRAL:
                    return value.isIntegral();
                case ValueType::NUMERIC:
                    return value.isNumeric();
                case ValueType::BOOL:
                    return value.isBool();
                case ValueType::OBJECT:
                    return value.isObject();
                case ValueType::ARRAY:
                    return value.isArray();
                default:
                    return false;
                }
            }

        private:
            std::string method_name;                     // 方法名
            ServiceCallback callback_func;               // 回调函数
            std::vector<ParametersDescribe> params_desc; // 参数描述
            ValueType return_type;                       // 返回值类型
        };

        class ServiceDescribeFactory
        {
        public:
            void setMethodName(const std::string &name)
            {
                method_name = name;
            }
            void setCallback(ServiceDescribe::ServiceCallback &cb)
            {
                callback_func = cb;
            }
            void setParamsDesc(const std::string &pname, ValueType vtype)
            {
                params_desc.push_back(ServiceDescribe::ParametersDescribe(pname, vtype));
            }
            void setReturnType(ValueType vtype)
            {
                return_type = vtype;
            }
            ServiceDescribe::ptr build()
            {
                return std::make_shared<ServiceDescribe>(std::move(method_name), std::move(params_desc), return_type, std::move(callback_func));
            }

        private:
            std::string method_name;                                      // 方法名
            ServiceDescribe::ServiceCallback callback_func;               // 回调函数
            std::vector<ServiceDescribe::ParametersDescribe> params_desc; // 参数描述
            ValueType return_type;                                        // 返回值类型
        };

        class ServiceManager
        {
        public:
            using ptr = std::shared_ptr<ServiceManager>;
            void insert(const ServiceDescribe::ptr &service)
            {
                std::unique_lock<std::mutex> lock(mtx);
                service_map[service->getMethod()] = service;
            }
            ServiceDescribe::ptr select(const std::string &method_name)
            {
                std::unique_lock<std::mutex> lock(mtx);
                if (service_map.find(method_name) != service_map.end())
                {
                    return service_map[method_name];
                }
                return ServiceDescribe::ptr();
            }
            void remove(const std::string &method_name)
            {
                std::unique_lock<std::mutex> lock(mtx);
                service_map.erase(method_name);
            }

        private:
            std::mutex mtx;
            std::unordered_map<std::string, ServiceDescribe::ptr> service_map;
        };

        class RpcRouter
        {
        public:
            using ptr = std::shared_ptr<RpcRouter>;
            RpcRouter() : service_manager(std::make_shared<ServiceManager>()) {}

            // 注册到Dispatcher模块针对rpc请求进行回调处理的业务函数
            void onMessage(const BaseConnection::ptr &conn, RpcRequest::ptr &request)
            {
                // 查询client请求方法描述，如果不存在，则返回错误
                ServiceDescribe::ptr service = service_manager->select(request->getMethod());
                if (service.get() == nullptr)
                {
                    LOG_ERROR("no such method: %s", request->getMethod().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_NOT_FOUND_SERVICE);
                }
                // 进行参数校验，如果参数类型不匹配，则返回错误
                if (!service->checkParams(request->getParams()))
                {
                    LOG_ERROR("params check failed %s", request->getMethod().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_INVALID_PARAMS);
                }
                // 调用回调函数
                Json::Value result;
                bool res = service->callback(request->getParams(), result);
                if (!res)
                {
                    LOG_ERROR("callback failed %s", request->getMethod().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_INTERNAL_ERROR);
                }
                // 返回结果
                return response(conn, request, result, RCode::RCODE_OK);
            }

            // 注册服务
            void registerMethod(const ServiceDescribe::ptr &service)
            {
                service_manager->insert(service);
            }

        private:
            void response(const BaseConnection::ptr &conn,
                          const RpcRequest::ptr &req,
                          const Json::Value &res, RCode rcode)
            {
                auto msg = MessageFactory::create<RpcResponse>();
                msg->setRCode(rcode);
                msg->setMessageType(jsonrpc::MType::RSP_RPC);
                msg->setRid(req->getRid());
                msg->setResult(res);
                conn->send(msg);
            }

        private:
            ServiceManager::ptr service_manager;
        };
    }
}